package com.xb.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.sms.v20210111.SmsClient;
import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;
import com.xb.model.domain.entity.Userinfo;
import com.xb.model.domain.vo.LoginResponseVO;
import com.xb.system.common.result.Result;
import com.xb.system.mapper.db1.UserMapper;
import com.xb.system.properties.TencentSmsProperties;
import com.xb.system.service.UserService;
import com.xb.system.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; // 仍需引入
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.regex.Pattern;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private TencentSmsProperties smsProperties;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private RestTemplate restTemplate;
    
    @Value("${promotion.callback.url}")
    private String promotionCallbackUrl;
    
    @Value("${promotion.callback.appSecret}")
    private String promotionAppSecret;
    
    private static final String PHONE_REGEX = "^1[3-9]\\d{9}$";
    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    @Override
    @Transactional
    @CachePut(value = "captcha", key = "#phone")
    public String generateCaptcha(String phone) {
        validatePhone(phone);
        String captcha = String.valueOf((int) ((Math.random() * 9 + 1) * 100000)); // 6 位验证码
        sendSms(phone, captcha);
        log.info("Generated captcha for phone {}: {}", phone, captcha);
        return captcha; // 返回值会被缓存到 Redis，5 分钟后过期
    }

    @Override
    @Transactional
    public Result<LoginResponseVO> loginByCaptcha(String phone, String captcha, String inviterId) {
        validatePhone(phone);
        String storedCaptcha = getCaptchaFromCache(phone);
        if (storedCaptcha == null || !captcha.equals(storedCaptcha)) {
            throw new RuntimeException("验证码错误或已过期");
        }

        Userinfo userInfo = findByPhone(phone);
        if (userInfo == null) {
            userInfo = new Userinfo();
            userInfo.setPhone(phone);
            userInfo.setCreateTime(LocalDateTime.now());
            userInfo.setUpdateTime(LocalDateTime.now());
            userInfo.setIsDeleted(0);
            if (inviterId != null && !inviterId.isEmpty()) {
                userInfo.setInviterId(inviterId);
            }
            saveUser(userInfo);
            
            if (inviterId != null && !inviterId.isEmpty()) {
                notifyPromotionSystem(inviterId, userInfo.getPhone(), userInfo.getCreateTime());
            }
        }

        clearCaptchaCache(phone);
        Long userId = userInfo.getId();
        String token = jwtUtil.generateToken(userId);
        boolean isFirstLogin = userInfo.getPassword() == null;
        LoginResponseVO responseVO = new LoginResponseVO(token, isFirstLogin);
        responseVO.getUser().setId(userInfo.getId());
        responseVO.getUser().setPhone(userInfo.getPhone());
        responseVO.getUser().setInviterId(userInfo.getInviterId());
        return Result.ok(responseVO);
    }

    @Override
    @Transactional
    public Result<LoginResponseVO> loginByPassword(String phone, String password) {
        validatePhone(phone);
        Userinfo userInfo = findByPhone(phone);
        if (userInfo == null || userInfo.getPassword() == null) {
            throw new RuntimeException("请先使用验证码登录并设置密码");
        }
        if (!passwordEncoder.matches(password, userInfo.getPassword())) {
            throw new RuntimeException("密码错误");
        }
        Long userId = userInfo.getId();
        String token = jwtUtil.generateToken(userId);
        LoginResponseVO responseVO = new LoginResponseVO(token, false);
        responseVO.getUser().setId(userInfo.getId());
        responseVO.getUser().setPhone(userInfo.getPhone());
        responseVO.getUser().setInviterId(userInfo.getInviterId());
        return Result.ok(responseVO);
    }

    @Override
    @Transactional
    public void setPassword(String phone, String password) {
        Userinfo userInfo = findByPhone(phone);
        if (userInfo == null) {
            throw new RuntimeException("用户不存在");
        }
        userInfo.setPassword(passwordEncoder.encode(password));
        userInfo.setUpdateTime(LocalDateTime.now());
        userMapper.updateById(userInfo);
    }

    @Override
    public Userinfo findByPhone(String phone) {
        return userMapper.selectOne(
                new QueryWrapper<Userinfo>()
                        .eq("phone", phone)
                        .eq("is_deleted", 0)
        );
    }

    @Override
    @Transactional
    public void saveUser(Userinfo userInfo) {
        userMapper.insert(userInfo);
    }

    public String getCaptchaFromCache(String phone) {
        // 直接通过 RedisTemplate 读取，key 格式需与存储时一致
        return redisTemplate.opsForValue().get(phone);
    }
    @CacheEvict(value = "captcha", key = "#phone")
    public void clearCaptchaCache(String phone) {
        // 清除 Redis 中的缓存
    }

    private void validatePhone(String phone) {
        if (!Pattern.matches(PHONE_REGEX, phone)) {
            throw new RuntimeException("仅支持中国 +86 手机号");
        }
    }

    private void sendSms(String phone, String captcha) {
        try {
            // 实例化一个认证对象，入参需要传入腾讯云账户 SecretId 和 SecretKey
            Credential cred = new Credential(smsProperties.getSecretId(), smsProperties.getSecretKey());

            // 实例化一个 HTTP 选项，可选，无特殊需求可跳过
            HttpProfile httpProfile = new HttpProfile();
            // 设置接入域名
            httpProfile.setEndpoint("sms.tencentcloudapi.com");

            // 实例化一个客户端配置对象，可指定超时时间等配置
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(httpProfile);

            // 实例化要请求产品的client对象，第二个参数是地域信息
            SmsClient client = new SmsClient(cred, "ap-guangzhou", clientProfile);

            // 实例化一个请求对象
            SendSmsRequest req = new SendSmsRequest();
            
            // 设置短信应用ID
            req.setSmsSdkAppId(smsProperties.getSdkAppId());
            
            // 设置短信签名内容
            req.setSignName(smsProperties.getSignName());
            
            // 设置模板ID
            req.setTemplateId(smsProperties.getTemplateId());
            
            // 设置模板参数
            String[] templateParams = {captcha};
            req.setTemplateParamSet(templateParams);
            
            // 设置下发手机号码，采用 E.164 标准，+[国家或地区码][手机号]
            String[] phoneNumbers = {"+86" + phone};
            req.setPhoneNumberSet(phoneNumbers);

            // 通过client对象调用SendSms方法发起请求，返回响应
            SendSmsResponse response = client.SendSms(req);
            
            log.info("Tencent SMS response: {}", SendSmsResponse.toJsonString(response));
            
            // 检查发送结果
            if (response.getSendStatusSet().length > 0) {
                String code = response.getSendStatusSet()[0].getCode();
                String message = response.getSendStatusSet()[0].getMessage();
                
                if ("Ok".equals(code)) {
                    log.info("SMS sent successfully to {}", phone);
                } else {
                    log.error("SMS sending failed to {}: code={}, message={}", phone, code, message);
                    
                    // 根据不同错误码返回不同的错误信息
                    if ("LimitExceeded.PhoneNumberDailyLimit".equals(code)) {
                        throw new RuntimeException("该手机号今日短信发送次数已达上限，请明天再试");
                    } else if ("LimitExceeded.PhoneNumberOneHourLimit".equals(code)) {
                        throw new RuntimeException("该手机号短信发送过于频繁，请一小时后再试");
                    } else if ("LimitExceeded.PhoneNumberSameContentDailyLimit".equals(code)) {
                        throw new RuntimeException("该手机号相同内容短信发送次数已达上限");
                    } else if ("FailedOperation.SignatureIncorrectOrUnapproved".equals(code)) {
                        throw new RuntimeException("短信签名不正确或未审批，请联系管理员");
                    } else if ("FailedOperation.TemplateIncorrectOrUnapproved".equals(code)) {
                        throw new RuntimeException("短信模板不正确或未审批，请联系管理员");
                    } else if ("InvalidParameterValue.IncorrectPhoneNumber".equals(code)) {
                        throw new RuntimeException("手机号格式不正确");
                    } else {
                        throw new RuntimeException("短信发送失败: " + message);
                    }
                }
            } else {
                log.error("SMS sending failed to {}: Empty response", phone);
                throw new RuntimeException("短信发送失败：服务返回为空");
            }
        } catch (TencentCloudSDKException e) {
            log.error("SMS service error for phone {}: {}", phone, e.getMessage());
            throw new RuntimeException("短信服务异常: " + e.getMessage());
        }
    }

    /**
     * 通知推广系统用户注册成功
     * @param inviterId 邀请人ID
     * @param inviteeId 被邀请人ID
     * @param registerTime 注册时间
     */
    private void notifyPromotionSystem(String inviterId, String inviteeId, LocalDateTime registerTime) {
        try {
            // 构建请求参数
            Map<String, Object> params = new HashMap<>();
            params.put("inviterCode", inviterId);
            params.put("inviteePhone", inviteeId);
            params.put("registerTime", registerTime);
            params.put("appId", "jlh"); // 当前应用的标识
            
            // 添加时间戳
            long timestamp = System.currentTimeMillis();
            params.put("timestamp", timestamp);
            
            // 生成签名
            String signContent = inviterId + inviteeId + "jlh" + timestamp + promotionAppSecret;
            String sign = org.springframework.util.DigestUtils.md5DigestAsHex(signContent.getBytes());
            params.put("sign", sign);
            
            // 异步执行回调，不阻塞主流程
            CompletableFuture.runAsync(() -> {
                try {
                    // 直接调用推广系统API
                    HttpHeaders headers = new HttpHeaders();
                    headers.setContentType(MediaType.APPLICATION_JSON);
                    HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(params, headers);
                    
                    String result = restTemplate.postForObject(promotionCallbackUrl, requestEntity, String.class);
                    log.info("推广系统回调结果: {}", result);
                } catch (Exception e) {
                    log.error("回调推广系统出错: {}", e.getMessage(), e);
                }
            });
        } catch (Exception e) {
            log.error("构建推广系统回调请求出错: {}", e.getMessage(), e);
        }
    }
}